﻿/*
 * Copyright 2012 Rene Prost, Registrite ja Infosüsteemide Keskus 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

namespace Xtee.Core.Envelope
{
    public class FirstTextContentOrUnprocessedtDetailSerializer : IFaultDetailSerializer
    { 
        public object Read(IXteeXmlReader xreader)
        {
            var stream = xreader.ReadNode();
            using (var reader = XteeXmlReader.InternalCreate(stream))
            {
                var value = AttempToReadFirstTextContent(reader);
                if (value != null)
                {
                    if (value.WasOnlyContent)
                    {
                        return value.Value;
                    }
                    return new UnprocessedFaultDetail(value.Value,stream); 
                }
            }
       
            return new UnprocessedFaultDetail(null,stream); 
        }

        private FirstTextContent AttempToReadFirstTextContent(XmlReader reader)
        {
            reader.Read();
            var startNode = reader.LocalName;
            reader.Read();
            if (reader.NodeType == XmlNodeType.Element)
            {
                var firstElementNode = reader.LocalName;
                reader.Read(); 
                if (IsTextContent(reader))
                {
                    return ReadTextContent(reader, firstElementNode, startNode);
                }
            }
            else if (IsTextContent(reader))
            {
                return ReadTextContent(reader, startNode, startNode);
            }
            return null;
        }

        private static FirstTextContent ReadTextContent(XmlReader reader, string firstElementNode, string startNode)
        {
            var firstValue = reader.Value;
            reader.Read(); 
            if (reader.LocalName == firstElementNode && reader.NodeType == XmlNodeType.EndElement)
            {
                reader.ReadEndElement();
                if (reader.EOF) return new FirstTextContent(true, firstValue);
                if (reader.LocalName == startNode && reader.NodeType == XmlNodeType.EndElement)
                {
                    reader.ReadEndElement();
                    if (reader.EOF) return new FirstTextContent(true, firstValue);
                }
            }
            return new FirstTextContent(false, firstValue);
        }

        private static bool IsTextContent(XmlReader reader)
        {
            return reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA;
        }

        private class FirstTextContent
        {
            public FirstTextContent(bool wasOnlyContent, string value)
            {
                WasOnlyContent = wasOnlyContent;
                Value = value == null ? string.Empty : value.Trim('\r', '\n', ' ', '\t');
            }

            public string Value { get; private set; }
            public bool WasOnlyContent { get; private set; }
        }


        public void Write(object faultDetail, IXteeXmlWriter writer)
        {
            if (faultDetail != null)
            {
                if (!(faultDetail is string))
                {
                    throw new SerializationException("For now i am able to serialize only string as fault detail. You can replace me with a much smarter implementation.");
                }
                writer.WriteElementCData("faultDetail", "", new Schema.XsdString((string)faultDetail).ToString());
            }
            else
            {
                writer.WriteAttributeString("xsi", "nil", null, "1");
            }
        }
    }
}